﻿using System.Collections.Generic;
using System.Security.Cryptography;
using System.Xml.Linq;
using Microsoft.EntityFrameworkCore.Storage.Json;
using ST.Core;
using ST.Core.Util;
using ST.ModelVM.ProtocolDefine;
using ST.ModelVM.ProtocolSim;
using ST.ModelVM.ProtocolSimHost;

namespace ST.Receiver.Tasks
{
    public class SimHostWorker
    {

        public Data.ProtocolSimHost ProtocolSimHost { get; set; }
        SimWorker SimWorker { get; set; }   
        public List<EquipmentAttributeVM> EquipmentAttributes { get; set; }    
        ModelVM.ProtocolDefine.ProtocolDefineVM ProtocolDefineVM { get; set; }
        
        List<UInt16Value> ListCs= new List<UInt16Value>();
        public Calc Calc { get; set; } = new Calc();
        ReqAndRevVM _ReqAndRevVM;
        public SimHostWorker(SimWorker sw, Data.ProtocolSimHost host) {
            this.SimWorker = sw; 
            this.ProtocolSimHost = host;
            EquipmentAttributes=new List<EquipmentAttributeVM>();
            _ReqAndRevVM = new ReqAndRevVM();
            _ReqAndRevVM.HostId=host.HostId;    
        }
        /// <summary>
        /// 第一次调用
        /// </summary>
        /// <returns></returns>  0 正常    BreakToken  1  EndToken 2    timeout 3
        public async Task<int> DoFirstAsync()
        {
            EquipmentAttributes.Clear();
            //初始化
            ProtocolDefineVM = ST.Core.Util.JSON.DeserializeObject<ModelVM.ProtocolDefine.ProtocolDefineVM>(SimWorker.ProtocolDefine.Content);
            var lcs=ST.Core.Util.JSON.DeserializeObject<List<ProtocolZSBCSValue>>(ProtocolSimHost.Content);
            ListCs.Clear();
            foreach (var mcs in lcs)
            {
                ListCs.Add(new UInt16Value { Id = mcs.Value, Name = mcs.Name });
            }
            foreach (var m in ProtocolDefineVM.QQZSBCS)
            {
                var len = 0;
                foreach (var mdata in m.Data)
                {
                    switch (mdata.DataType.ToLower())
                    {
                        case "bit":mdata.DataLen = 1;break;
                        case "byte": mdata.DataLen = 1; break;
                        case "uint16": mdata.DataLen = 2; break; 
                        case "int": mdata.DataLen = 4; break;
                        case "float": mdata.DataLen = 4; break;
                    }
                    mdata.Index = len;
                    len += mdata.DataLen;
                }
                m.LoopDataByteNum = len;
            }
            foreach (var m in ProtocolDefineVM.QQGDSJ)
            {
                var len = 0;
                foreach (var mdata in m.Data)
                {
                    switch (mdata.DataType.ToLower())
                    {
                        case "bit": mdata.DataLen = 1; break;
                        case "byte": mdata.DataLen = 1; break;
                        case "uint16": mdata.DataLen = 2; break;
                        case "int": mdata.DataLen = 4; break;
                        case "float": mdata.DataLen = 4; break;
                    }
                    mdata.Index = len;
                    len += mdata.DataLen;
                }
                m.LoopDataByteNum = len;
            }
            foreach (var m in ProtocolDefineVM.QQXHSJ)
            {
                var len = 0;
                foreach (var mdata in m.Data)
                {
                    switch (mdata.DataType.ToLower())
                    {
                        case "bit": mdata.DataLen = 1; break;
                        case "byte": mdata.DataLen = 1; break;
                        case "uint16": mdata.DataLen = 2; break;
                        case "int": mdata.DataLen = 4; break;
                        case "float": mdata.DataLen = 4; break;
                    }
                    mdata.Index = len;
                    len += mdata.DataLen;
                }
                m.LoopDataByteNum = len;
            }



            //请求参数
            var r = 0;
            r = await QQCSAsync();
            if (r != 0)
            {
                return r;
            }
            //请求主设备数据
            r = await QQGDSJAsync(true);
            if (r != 0)
            {
                return r;
            }
            //请求子设备数据
            r = await QQXHSJAsync(true);
            if (r != 0)
            {
                return r;
            }


            return 0;
        }

        /// <summary>
        /// 循环调用 
        /// </summary>
        /// <returns></returns>  0 正常    BreakToken  1  EndToken 2    timeout 3
        public async Task<int> DoLoopAsync()
        {
            var r = 0;
            //请求主设备数据
            r = await QQGDSJAsync(false);
            if (r != 0)
            {
                return r;
            }
            //请求子设备数据
            r = await QQXHSJAsync(false);
            if (r != 0)
            {
                return r;
            }
            return r;
        }

        /// <summary>
        /// 循环调用 
        /// </summary>
        /// <returns></returns>  0 正常    BreakToken  1  EndToken 2    timeout 3   检验失败4
        public async Task<int> CmdAsync(ProtocolCmdVM mm)
        {
           
            var mcd = ProtocolDefineVM.GDZL.Where(a => a.Name == mm.Cmd).FirstOrDefault();
            if (mcd == null)
            {
                throw new ST.Core.MyException("无效指令");
            }
            var data = new byte[mcd.Data.Count+2  ];
          
            var md = new UInt16Value { Name = "设备编号", Id = Convert.ToUInt16(mm.DeviceCode) };

            data[0] = ProtocolSimHost.HostId;
            data[1] = mcd.Gnm;
            for(var i = 2; i < data.Length; i++)
            {
                data[i ] =Convert.ToByte( Calc.CalcUInt16Args(mcd.Data[i-2 ].ByteFml,md) );
            }
           


            _ReqAndRevVM.Gnm = mcd.Gnm;
            _ReqAndRevVM.SendMemo = $"请求指令:{mm.Cmd}";
            _ReqAndRevVM.SendData = data;
            _ReqAndRevVM.PlanRevByteCount = 3;

            return await SimWorker.CmdAndRev(this, _ReqAndRevVM); 
        }

        public async Task<int> QQCSAsync()
        {
            foreach(var m in ProtocolDefineVM.QQZSBCS)
            {

                var len = m.LoopDataByteNum;

                _ReqAndRevVM.Gnm = m.Gnm;
                _ReqAndRevVM.BitData = false;
                _ReqAndRevVM.StartAddress = m.StartAddress;
                _ReqAndRevVM.ReqLen =Convert.ToUInt16( len);
                _ReqAndRevVM.SendMemo = $"请求参数 {m.Name}";
                await SimWorker.SendAndRev(this, _ReqAndRevVM);
                if (_ReqAndRevVM.Result != 0)
                {
                    return _ReqAndRevVM.Result; 
                }
                foreach (var mcs in m.Data)
                {
                    if (!string.IsNullOrEmpty(mcs.Name))
                    {
                        var v = SimWorker.GetUInt16FromModbusData(_ReqAndRevVM.RevData, mcs.Index);
                        var mcsv = ListCs.Where(a => a.Name == mcs.Name).FirstOrDefault();
                        if (mcsv != null)
                        {
                            mcsv.Id = v;
                        }
                        else
                        {
                            ListCs.Add(new UInt16Value { Id = v, Name = mcs.Name });
                        }
                    }
                }

            }

            
            return 0;
        }
        EquipmentAttributeVM AddEquipmentAttribute(int DeviceCode, string PropCode, string DeviceName = "", string PropName="")
        {
            var m = this.EquipmentAttributes.Where(a => a.DeviceCode == DeviceCode && a.PropCode == PropCode).FirstOrDefault();
            if (m != null)
            {
                return m;
            }
            m = new EquipmentAttributeVM { DeviceCode = DeviceCode, PropCode = PropCode, PropName= PropName };
            m.DeviceName = DeviceName + m.DeviceCode.ToString("D4");
            EquipmentAttributes.Add(m);
            return m;
        }
        void ReadEquipmentAttribute(ProtocolQQSJRowVM row, byte[] data,int Index, int DeviceCode, string DeviceName = "")
        {
            if(row.PropType== "预留")
            {
                return;
            }
            var mattr = AddEquipmentAttribute(DeviceCode, row.PropCode, DeviceName,row.PropName);

            object value = null;
            switch (row.DataType.ToLower())
            {
                case "bit":
                    value= SimWorker.GetBitFromModbusData(data,row.Index+ Index);
                    break;
                case "byte":
                    value = SimWorker.GetByteFromModbusData(data, row.Index + Index);
                    break;
                case "uint16":
                    value = SimWorker.GetUInt16FromModbusData(data, row.Index + Index);
                    break;
                case "int":
                    value = SimWorker.GetInt32FromModbusData(data, row.Index + Index);
                    break;
                case "float":
                    value = SimWorker.GetFloatFromModbusData(data, row.Index + Index);
                    break;
                default:
                    throw new ST.Core.MyException("非法类型");
            }
            switch (row.PropType)
            {
                case "状态":
                    {
                        var mzd=FindSJZDValue(row.SJZDKey, value);
                        if(mzd != null)
                        { 
                            mattr.StateValue = mzd.Name;
                            mattr.BJStatus = mzd.BJStatus;
                        }
                    }
                    break;
                case "值":
                    {
                        var v = Convert.ToDecimal(value);
                        switch (mattr.Scale)
                        {
                            case 1:
                                v = v / 10.0M;
                                break;
                            case 2:
                                v = v / 100.0M;
                                break;
                            case 3:
                                v = v / 1000.0M;
                                break;
                            default:
                                break;
                        }
                        if (!string.IsNullOrEmpty(row.Fml))
                        {
                            var fml = row.Fml.Replace("值", v.ToString());
                            v = this.Calc.CalcDecimalArgs(fml);
                        }
                        mattr.NumValue = v;
                    }
                    break;
                case "类型":
                    {
                        var mzd = FindSJZDValue(row.SJZDKey, value);
                        if (mzd != null)
                        {
                            mattr.PropName = mzd.Name;
                        }
                    }
                    break;
                case "单位":
                    {
                        var mzd = FindSJZDValue(row.SJZDKey, value);
                        if (mzd != null)
                        {
                            mattr.Unit = mzd.Name;
                        }
                    }
                    break;
                case "精度":
                    {
                        mattr.Scale=Convert.ToByte(value);
                    }
                     
                    break;
                case "上限":
                    {
                        var v = Convert.ToDecimal(value);
                        switch (mattr.Scale)
                        {
                            case 1:
                                v = v / 10.0M;
                                break;
                            case 2:
                                v = v / 100.0M;
                                break;
                            case 3:
                                v = v / 1000.0M;
                                break;
                            default:
                                break;
                        }
                        mattr.ValueHigh = v;
                    }

                    break;
                case "下限":
                    {
                        var v = Convert.ToDecimal(value);
                        switch (mattr.Scale)
                        {
                            case 1:
                                v = v / 10.0M;
                                break;
                            case 2:
                                v = v / 100.0M;
                                break;
                            case 3:
                                v = v / 1000.0M;
                                break;
                            default:
                                break;
                        }
                        mattr.ValueLow = v;
                    }
                    break;
                case "预留":
                    break;
                default:
                    throw new ST.Core.MyException("非法类型");
            }
              
        }
        ProtocolSJZDRowVM FindSJZDValue(  string key,object v)
        {
            ProtocolSJZDVM msjzd=null;
            for (var i = 0; i <this.ProtocolDefineVM.SJZD.Count; i++)
            {
                if (this.ProtocolDefineVM.SJZD[i].Name == key)
                {
                    msjzd= this.ProtocolDefineVM.SJZD[i];
                }
            }
            if (msjzd == null)
            {
                return null;
            }
            var uv = Convert.ToUInt16(v);
            foreach(var mrow in msjzd.Data)
            {
                if(mrow.IMax.HasValue&&mrow.IMax.HasValue)
                {
                    if (uv >= mrow.IMin.Value && uv <= mrow.IMax.Value)
                    {
                        return mrow;
                    }
                }
                else if(mrow.IMin.HasValue)
                {
                    if (uv >= mrow.IMin.Value )
                    {
                        return mrow;
                    }
                }
                else if(mrow.IMax.HasValue)
                {
                    if (  uv <= mrow.IMax.Value)
                    {
                        return mrow;
                    }
                }
            }
            return null;
        }
        public async Task<int> QQGDSJAsync(bool IsFirst)
        {
            foreach (var m in ProtocolDefineVM.QQGDSJ)
            {
                if(!IsFirst && !m.LoopStatus)
                {
                    continue;
                }
                if (m.LoopSencond != 0)
                {
                    if ((DateTime.Now - m.LstReqDt).TotalSeconds < m.LoopSencond)
                    {
                        continue;
                    }
                }
                 var len = m.LoopDataByteNum;

                _ReqAndRevVM.Gnm = m.Gnm;
                _ReqAndRevVM.BitData = false;
                _ReqAndRevVM.StartAddress = m.StartAddress;
                _ReqAndRevVM.ReqLen = Convert.ToUInt16(len);
                _ReqAndRevVM.SendMemo = $"请求主设备 {m.Name}";
                await SimWorker.SendAndRev(this, _ReqAndRevVM);
                if (_ReqAndRevVM.Result != 0)
                {
                    return _ReqAndRevVM.Result;
                }
                foreach (var msj in m.Data)
                {
                    ReadEquipmentAttribute(msj, _ReqAndRevVM.RevData,0, 0);
                     
                }
                m.LstReqDt = DateTime.Now;
            }
            return 0;
        }
        public async Task<int> QQXHSJAsync(bool IsFirst)
        {
           
            foreach (var m in ProtocolDefineVM.QQXHSJ)
            {
                if (!IsFirst && !m.LoopStatus)
                {
                    continue;
                }
                if (m.LoopSencond != 0)
                {
                    if ((DateTime.Now - m.LstReqDt).TotalSeconds < m.LoopSencond)
                    {
                        continue;
                    }
                }
                var LoopBegin = Calc.CalcUInt16(m.LoopBeginFml, ListCs);
                var LoopEnd = Calc.CalcUInt16(m.LoopEndFml, ListCs);
                var LoopIndex = LoopBegin;
                var StartAddress = m.StartAddress;

                while (LoopIndex <=LoopEnd)
                {
                    // 计算本次请求的组数
                    var LoopReqNum = Math.Min(m.LoopReqNum, LoopEnd - LoopIndex + 1);

                    if (m.BitData)
                    {
                        // 按bit请求，确保总bit数是8的倍数
                        var totalBits = LoopReqNum * m.LoopDataByteNum * 8;
                        var remainder = totalBits % 8;
                        if (remainder != 0)
                        {
                            LoopReqNum -= (remainder / m.LoopDataByteNum / 8);
                            if (LoopReqNum <= 0) LoopReqNum = 1;
                        }
                    }
                    else
                    {
                        // 按寄存器请求，确保寄存器数量是整数
                        var totalRegisters = LoopReqNum * m.LoopDataByteNum / 2;
                        var remainder = (LoopReqNum * m.LoopDataByteNum) % 2;
                        if (remainder != 0)
                        {
                            LoopReqNum -= 1;
                        }
                        if (LoopReqNum <= 0) LoopReqNum = 1;
                    }

                    // 计算请求长度
                    var reqLen = m.BitData ?
                        (LoopReqNum * m.LoopDataByteNum * 8 + 7) / 8 : // 按bit请求的长度
                        LoopReqNum * m.LoopDataByteNum / 2;           // 按寄存器请求的长度

                   
                    _ReqAndRevVM.Gnm = m.Gnm;
                    _ReqAndRevVM.BitData = m.BitData;
                    _ReqAndRevVM.StartAddress = StartAddress;
                    _ReqAndRevVM.ReqLen = Convert.ToUInt16(reqLen );
                    if (!m.BitData)
                    {
                        _ReqAndRevVM.ReqLen *= 2;
                    }
                    _ReqAndRevVM.SendMemo = $"请求子设备 {m.Name} {LoopIndex}~{LoopIndex+ LoopReqNum-1}";

                    await SimWorker.SendAndRev(this, _ReqAndRevVM);
                    if (_ReqAndRevVM.Result != 0)
                    {
                        return _ReqAndRevVM.Result;
                    }
                    var index = 0;
                    for (var iDeviceCode= LoopIndex; iDeviceCode < LoopIndex+LoopReqNum; iDeviceCode++)
                    {
                        var DeviceCode = Calc.CalcUInt16Args(m.DeviceCodeFml, new UInt16Value { Name = "循环序号", Id = iDeviceCode });
                        
                        foreach (var msj in m.Data)
                        {
                            ReadEquipmentAttribute(msj, _ReqAndRevVM.RevData,index, DeviceCode,m.Name);
                            
                        }
                        index += m.LoopDataByteNum;
                    }
                 
                    
                    // 更新索引和地址
                    LoopIndex += Convert.ToUInt16(LoopReqNum);
                    StartAddress += Convert.ToUInt16(reqLen);
                }
                m.LstReqDt = DateTime.Now;
            }
            return 0;
        }

    }
}
